package com.fourforfo.fourmall.auth.web;

import com.alibaba.fastjson.TypeReference;
import com.fourforfo.common.constant.AuthConstant;
import com.fourforfo.common.exception.BizCodeEnum;
import com.fourforfo.common.utils.R;
import com.fourforfo.common.vo.MemberRespVO;
import com.fourforfo.fourmall.auth.feign.MemberFeignService;
import com.fourforfo.fourmall.auth.feign.ThirdPartyFeignService;
import com.fourforfo.fourmall.auth.vo.UserLoginVO;
import com.fourforfo.fourmall.auth.vo.UserRegisterVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

@Slf4j
@Controller
public class LoginController {


    @Autowired
    ThirdPartyFeignService thirdPartyFeignService;

    @Autowired
    MemberFeignService memberFeignService;

    @Autowired
    StringRedisTemplate redisTemplate;


    @PostMapping("/login1")
    public String login(@Valid UserLoginVO vo, BindingResult result, RedirectAttributes attributes, HttpSession session){

        Map<String,String> errors = new HashMap<>();
        if(result.hasErrors()){
            for (FieldError fieldError : result.getFieldErrors()) {
                if(errors.containsKey(fieldError.getField())){
                    String priorMsg = errors.get(fieldError.getField());
                    errors.put(fieldError.getField(),priorMsg+";"+fieldError.getDefaultMessage());
                }else{
                    errors.put(fieldError.getField(),fieldError.getDefaultMessage());
                }
            }
            attributes.addFlashAttribute("errors",errors);
            //校验出错 ，转发到登录页
            return "redirect:http://auth.fourmall.com/login.html";
        }

        R r = memberFeignService.login(vo);
        if(r.getCode()==0){
            //成功

            MemberRespVO respVO = r.getData(new TypeReference<MemberRespVO>() {});
            log.info("登录成功，用户信息为：{}",respVO.toString());
            session.setAttribute(AuthConstant.LOGIN_USER,respVO);
            return "redirect:http://fourmall.com";
        }else{
            errors.put("msg",r.getMsg());
            attributes.addFlashAttribute("errors",errors);

            //失败
            return "redirect:http://auth.fourmall.com/login.html";
        }
    }

    @PostMapping("/register")
    public String register(@Valid UserRegisterVO userRegisterVO, BindingResult result, RedirectAttributes attributes){
        Map<String,String> errors = new HashMap<>();
        String success = "redirect:http://auth.fourmall.com/login.html";
        String error = "redirect:http://auth.fourmall.com/reg.html";
        if(result.hasErrors()){
            for (FieldError fieldError : result.getFieldErrors()) {
                if(errors.containsKey(fieldError.getField())){
                    String priorMsg = errors.get(fieldError.getField());
                    errors.put(fieldError.getField(),priorMsg+";"+fieldError.getDefaultMessage());
                }else{
                    errors.put(fieldError.getField(),fieldError.getDefaultMessage());
                }
            }
            attributes.addFlashAttribute("errors",errors);
            //校验出错 ，转发到注册页
            return error;
        }
        //检验通过才执行注册逻辑,调用远程服务执行注册
        //1. 校验验证码是否一致
        //1.1 前端传来的验证码
        String code = userRegisterVO.getCode();
        //1.2 redis中缓存的验证码
        String cachedStr = redisTemplate.opsForValue().get(AuthConstant.SMS_CODE_CACHE_PREFIX + userRegisterVO.getPhone());
        if(StringUtils.isEmpty(cachedStr)){
            errors.put("code","验证码为空，请重新发送验证码!");
            attributes.addFlashAttribute(errors);
            return error;
        }
        String[] strings = cachedStr.split("_");
        if(code.equals(strings[0])){
            //验证码通过，调用远程服务注册
            R r = memberFeignService.register(userRegisterVO);
            if(r.getCode()==0){
                //清楚缓存中的验证码,令牌机制，使用过了就立即清除，不能等待其自动过期
                redisTemplate.delete(AuthConstant.SMS_CODE_CACHE_PREFIX + userRegisterVO.getPhone());
                return success;
            }else{
                errors.put("msg",r.getMsg());
                attributes.addFlashAttribute(errors);
                return error;
            }
        }else{
            errors.put("code","验证码输入错误，请重新输入!");
            attributes.addFlashAttribute(errors);
            return error;
        }
    }

    /**
     * 发送一个请求直接跳转到一个页面
     * @param phone
     * @return
     */
    @ResponseBody
    @GetMapping("/sms/sendcode")
    public R sendCode(@RequestParam("phone") String phone){
        boolean matches = Pattern.matches("^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$", phone);
        if(!matches){
            return R.error(1403,"手机号格式不正确");
        }

        //TODO 接口防刷
        /**
         * 使用电话号码作为key
         * key = prefix+phone
         * value = code+currentTime
         */
        String redisCode = redisTemplate.opsForValue().get(AuthConstant.SMS_CODE_CACHE_PREFIX + phone);
        if(!StringUtils.isEmpty(redisCode)){
            String[] s = redisCode.split("_");
            long codeTime = Long.parseLong(s[1]);
            //60内的请求不会调用第三方短信接口
            if(System.currentTimeMillis() - codeTime < 60000){
                return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(),BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
            }
        }

        /**
         * 使用ip地址作为key
         */

        String code = UUID.randomUUID().toString().substring(0,5)+"_"+System.currentTimeMillis();

//TODO 伪发送验证码        R r = thirdPartyFeignService.sendCode(phone,code.split("_")[0]);
        R r = R.ok();
        if(r.getCode()!=0){
            //说明发送验证码失败
            return r;
        }else{
            //2. 验证码的再次校验，redis存key-phone,value-code,key有一个同一前缀sms:code用于与其他缓存数据做划分
            redisTemplate.opsForValue().set(AuthConstant.SMS_CODE_CACHE_PREFIX+phone,code,5, TimeUnit.MINUTES);
            return R.ok();
        }

    }


    @GetMapping("/login.html")
    public String loginPage(HttpSession httpSession){
        Object attribute = httpSession.getAttribute(AuthConstant.LOGIN_USER);
        if(attribute == null){
            return "/login";
        }else{
            return "redirect:http://fourmall.com";
        }

    }

    @GetMapping("/reg.html")
    public String regPage(){
        return "reg";
    }
}
